package cool.doudou.doudada.iot.codec.config;

import cool.doudou.doudada.iot.codec.core.listener.BundleListener;
import cool.doudou.doudada.iot.codec.core.logger.FelixLogger;
import cool.doudou.doudada.iot.codec.core.processor.BundleStateChangeBeanPostProcessor;
import cool.doudou.doudada.iot.codec.properties.IotCodecProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.felix.framework.Felix;
import org.apache.felix.framework.cache.BundleCache;
import org.apache.felix.framework.util.FelixConstants;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import javax.annotation.PreDestroy;
import java.util.HashMap;
import java.util.Map;

/**
 * IotCodecConfig
 *
 * @author jiangcs
 * @since 2022/09/29
 */
@Slf4j
public class IotCodecConfig {
    private Framework framework;

    @Bean
    public BundleContext bundleContext() {
        return framework.getBundleContext();
    }

    @Bean
    public BundleStateChangeBeanPostProcessor bundleStateChangeBeanPostProcessor() {
        return new BundleStateChangeBeanPostProcessor();
    }

    @Autowired
    public void start(IotCodecProperties iotCodecProperties) {
        log.info("framework starting");

        Map<String, Object> configMap = new HashMap<>(5);
        // 容器启动时，清理缓存目录；若不清理，则已缓存Bundle执行install后状态直接为Active，上下文不触发Listener
        configMap.put(Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
        // 缓存目录
        configMap.put(BundleCache.CACHE_ROOTDIR_PROP, iotCodecProperties.getCachePath());
        // Felix日志等级
        configMap.put(FelixConstants.LOG_LEVEL_PROP, iotCodecProperties.getLogLevel());
        // Felix日志类
        configMap.put(FelixConstants.LOG_LOGGER_PROP, new FelixLogger());
        // 需额外引入包集合
        configMap.put(FelixConstants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, iotCodecProperties.getExtraPackage());

        try {
            framework = new Felix(configMap);
            framework.start();

            // 初始化 监听器
            BundleListener.init(framework.getBundleContext());

            log.info("framework started");
        } catch (BundleException e) {
            log.error("framework start exception: ", e);
        }
    }

    @PreDestroy
    public void stop() {
        log.info("framework stopping");

        try {
            framework.stop();
            framework.waitForStop(0);

            log.info("framework stopped");
        } catch (BundleException | InterruptedException e) {
            log.error("framework stop exception: ", e);
        }
    }
}
